﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Slaks.Graphs.Category;
using System.IO;
using Slaks.Readers;
using Slaks.Filters;
using TextParsing;
using Slaks.DocumentSerialization.TermIdInfo;
using System.Collections;
using Slaks.DocumentSerialization.ParsedFiles;
using Slaks.Graphs;
using Slaks.DocumentSerialization.Document;
using Slaks.Graphs.GraphBuilder;
using Slaks.Graphs.Algorithms;
using DataInput;
using Slaks.Graphs.Analysis;

namespace UI
{
    public abstract class ExperimentItem 
    {
        public const String ResultsFileNameParam = "ResultsFileName";
        public const String CategoryFileNameParam = "CategoryFileName";
        public const String SourceFolderParam = "SourceFolder";
        public const String SkipParsingParam = "SkipParsing";
        public const String TargetFolderParam = "TargetFolder";
        public const String RemoveStopWordsParam = "RemoveStopWords";
        public const String IterationsParam = "Iterations";

        private List<Field> fields;
        protected String _ResultsFileName = "";
        protected String _categoryFileName;
        protected CategoriesFile _categoriesFile;
        protected String _sourceFolder;
        protected Boolean _SkipParsing;
        protected String _targetFolder;
        protected Encoding _encoding = Encoding.UTF8;
        protected TermIdInfoMap map;
        protected IList _parsedFilesList;
        protected GraphList Graphs;        
        protected GraphBuilderBase RepresentationType;
        protected int _iterations;
        protected string _collectionName;
        private string _stopWordsFile;
        private GraphDistanceBase _distanceMeasure;
        protected Measures measures;
        private String _algorithmName;

        protected string StopWordsFile
        {
            get { return _stopWordsFile; }
            set { _stopWordsFile = value; }
        }
        

        protected String SourceFolder
        {
            get { return _sourceFolder; }
            set { _sourceFolder = value; }
        }

        protected GraphDistanceBase DistanceMeasure
        {
            get { return _distanceMeasure; }
            set { _distanceMeasure = value; }
        }

        protected string CollectionName
        {
            get { return _collectionName; }
            set { _collectionName = value; }
        }

        public int Iterations
        {
            get { return _iterations; }
            set { _iterations = value; }
        }

        public IList ParsedFilesList
        {
            get { return _parsedFilesList; }
        }

        public Encoding Encoding
        {
            get { return _encoding; }
            set { _encoding = value; }
        }        

        public String TargetFolder
        {
            get { return _targetFolder; }
            set { _targetFolder = value; }
        }
        
        public Boolean SkipParsing
        {
            get { return _SkipParsing; }
            set { _SkipParsing = value; }
        }

        public String CategoryFileName
        {
            get { return _categoryFileName; }
            set { _categoryFileName = value; }
        }

        protected String ResultsFileName
        {
            get { return _ResultsFileName; }
            set { _ResultsFileName = value; }
        }

        public List<Field> Fields
        {
            get { return fields; }
            set { fields = value; }
        }

        public string AlgorithmName
        {
            get { return _algorithmName; }
            set { _algorithmName = value; }
        }

        public String toDisplayFields()
        {
            StringBuilder str = new StringBuilder ();
            for (int i = 0; i < fields.Count; i++)
            {
                if (fields[i].Value is List<Object>)
                {
                    str.Append(fields[i].FieldName + "=");
                    List<Object> values = (List<Object>) fields[i].Value;
                    for ( int k = 0; k < values.Count; k++ )
                    {
                        str.Append(values[k].ToString());
                        str.Append("|");
                    }
                    str.Length--;
                }
                else
                {
                    str.Append(fields[i].FieldName + "=" + fields[i].Value.ToString());
                }
                if (i < fields.Count - 1)
                    str.Append(",");
            }
            return str.ToString();
        }


        public ExperimentItem(List<Field> fields, TaskType task, String algorithmName )
        {
            this.AlgorithmName = algorithmName;
            this.fields = fields;
            for ( int i = 0; i < fields.Count; i++ )
            {
                if (fields[i].FieldName == GraphBuilderBase.BuilderTypeParam)
                    RepresentationType = GraphBuilderFactory.Instance.GetInstance(fields[i].Value.ToString());
                if (fields[i].FieldName == GraphDistanceBase.DistanceAlgorithmParam)
                    DistanceMeasure = DistanceAlgFactory.Instance.GetInstance(fields[i].Value.ToString());
                if (fields[i].FieldName == IterationsParam)
                    Iterations = int.Parse ( fields[i].Value.ToString ());
                if (fields[i].FieldName == ResultsFileNameParam)
                    ResultsFileName = fields[i].Value.ToString();
                if (fields[i].FieldName == SourceFolderParam)
                {
                    SourceFolder = fields[i].Value.ToString();
                    CollectionName = SourceFolder;
                }
                if (fields[i].FieldName == CategoryFileNameParam )
                {
                    _categoryFileName = fields[i].Value.ToString();
                }
                if (fields[i].FieldName == Measures.measuresParam)
                {
                    measures = new Measures(task);
                    List<Object> currentFields = ( List<Object> ) fields [ i ].Value;
                    measures.setMeasures(currentFields.Select(field => field.ToString()).ToArray());
                }
                if (fields[i].FieldName == TargetFolderParam)
                    TargetFolder = fields[i].Value.ToString();
                if (fields[i].FieldName == SkipParsingParam)
                    SkipParsing = fields[i].Value.ToString() == "1";
                if (fields[i].FieldName == RemoveStopWordsParam)
                    _stopWordsFile = ( fields [ i ].Value != null && fields [ i ].Value.ToString().Trim().Length > 0 ) ? fields[i].Value.ToString() : null;
            }
        }

        public virtual void runExperiment()
        {
            ReadCategories();
            ParseDocuments();
            LoadGraphs();
            //SetDistanceMeasure();
        }

        private void ReadCategories()
        {
            _categoriesFile = new CategoriesFile();
            _categoriesFile.FillCateogriesFromFile(_categoryFileName);
        }        

        private void ParseDocuments()
        {
            try
            {
                if (!SkipParsing)
                {
                    var filesToParse = Directory.GetFiles(_sourceFolder, "*.htm?");
                    if (!Directory.Exists(_targetFolder))
                        Directory.CreateDirectory(_targetFolder);
                    var bufferReaderCore = new TermBufferReader(new EnglishTermFilter());
                    var structureConstruction = new StructureConstruction(bufferReaderCore, _targetFolder, _encoding,
                                                                          _stopWordsFile, null);
                    structureConstruction.ProceedParsing(filesToParse);

                    map = structureConstruction.TermIdMap;
                    _parsedFilesList = ParsedFiles.ReadXml(structureConstruction.ParsedFileList);
                }
                else
                {
                    const string parsedFileListXml = @"parsed_file_list.xml";
                    string parsedFilelistName = Path.Combine(_targetFolder, parsedFileListXml);
                    if (File.Exists(parsedFilelistName))
                    {
                        _parsedFilesList = ParsedFiles.ReadXml(parsedFilelistName);
                    }
                    const string termIdMap = @"term_id_info.xml";
                    string mapFileName = Path.Combine(_targetFolder, termIdMap);
                    if (File.Exists(mapFileName))
                    {
                        map = TermIdInfo.ReadXml(mapFileName);
                    }
                }

            }
            catch (Exception exception)
            {
                _parsedFilesList = null;
                map = null;
            }
        }

        private void LoadGraphs()
        {
            if (Graphs == null)
            {
                Graphs = new GraphList();
            }


            foreach (string s in _parsedFilesList)
            {

                Document document = Xml2Document.ReadXml(s);

                GraphBuilderBase representation = RepresentationType;
                try
                {
                    Graph newgraph;
                    if (representation != null)
                    {
                        newgraph = representation.Build(document, map, fields );
                        newgraph.Category = _categoriesFile.DocumentToCategoryMap[Path.GetFileName(newgraph.Name)];
                    }

                    else throw new Exception("Invalid representation : " + RepresentationType);

                    Graphs.Add(newgraph);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);

                    //                    numberOfMissedGraphs++;
                }
            }
        }

        public void SaveResults(int iteration, Dictionary<String, Object> measures)
        {

            StreamWriter outputFile;
            StringBuilder str = new StringBuilder();
            outputFile = new StreamWriter(ResultsFileName, true);
            if (iteration == 0)
            {
                for (int i = 0; i < fields.Count; i++)
                {
                    if (fields[i].ForOutput)
                    {
                        str.Append(fields[i].FieldName);
                        str.Append(",");
                    }
                }
                str.Append("CollectionName, iteration, RepresentationType,");
                foreach (KeyValuePair<String,Object> de in measures)
                {
                    str.Append(de.Key);
                    str.Append(",");
                }
                str.Length--;
                outputFile.WriteLine(str.ToString());
            }
            str.Length = 0;
            for (int i = 0; i < fields.Count; i++)
            {
                if (fields[i].ForOutput)
                {
                    str.Append(fields[i].Value.ToString());
                    str.Append(",");
                }
            }
            str.Append(CollectionName);
            str.Append(',');
            str.Append(iteration);
            str.Append(',');
            str.Append(RepresentationType.getBuilderType());
            str.Append(',');
            foreach (KeyValuePair<String, Object> de in measures)
            {
                str.Append(de.Value.ToString());
                str.Append(',');

            }
            str.Length--;
            outputFile.WriteLine(str.ToString());
            outputFile.Close();
        }
    }
}
